package com.bestom.waterquality.logic;

import android.Manifest;
import android.content.Context;
import android.content.pm.PackageManager;
import android.hardware.usb.UsbDevice;
import android.text.method.ScrollingMovementMethod;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.ArrayAdapter;
import android.widget.EditText;
import android.widget.TextView;

import androidx.annotation.NonNull;
import androidx.appcompat.widget.SwitchCompat;
import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;
import androidx.fragment.app.FragmentActivity;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;

import com.bestom.waterquality.R;
import com.bestom.waterquality.adapter.DeviceAdapter;
import com.bestom.waterquality.entity.DeviceEntity;
import com.bestom.waterquality.entity.SerialEntity;
import com.bestom.waterquality.ui.CustomTextView;
import com.bestom.waterquality.util.FormatUtil;
import com.bestom.waterquality.util.ToastUtil;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;

import cn.wch.ch934xlib.CH934XManager;
import cn.wch.ch934xlib.callback.IUsbStateChange;
import cn.wch.ch934xlib.chip.ChipType;
import cn.wch.ch934xlib.exception.ChipException;
import cn.wch.ch934xlib.exception.NoPermissionException;
import cn.wch.ch934xlib.exception.UartLibException;
import cn.wch.ch934xlib.utils.LogUtil;

/**
 * 485设置
 */
public class Four85Set {

    private static final String TAG = "Four85Set";
    private Four85Set() { }

    private static Four85Set _instance = null;

    public static Four85Set getInstance() {
        if (_instance == null)
            _instance = new Four85Set();
        return _instance;
    }

    private EditText command1;
    private TextView receive1;
    private ArrayAdapter<String> adapter;
    private Context mContext;
    private FragmentActivity mActivity;
    private View mView;
    //保存各个串口的接收计数
    HashMap<String, Integer> readCountMap=new HashMap<>();
    //已打开的设备列表
    final Set<UsbDevice> devices= Collections.synchronizedSet(new HashSet<UsbDevice>());
    Thread readThread;
    boolean flag=false;
    public void setDataAndListen(FragmentActivity activity, Context context, View view){

        mActivity = activity;
        mContext = context;
        mView = view;
        if(!UsbFeatureSupported()){
            showToast("系统不支持USB Host功能");
            System.exit(0);
            return;
        }

        initUI();
        readThread=new ReadThread();
        readThread.start();
        enumDevice();
        /*Spinner initiateMode1 = view.findViewById(R.id.initiate_mode_1);
        adapter = new ArrayAdapter<>(context, R.layout.serial_port_item, getAllDevices());
        initiateMode1.setAdapter(adapter);
        Spinner baudRate1 = view.findViewById(R.id.baud_rate_1);
        Spinner dataBits1 = view.findViewById(R.id.data_bits_1);
        Spinner parityBits1 = view.findViewById(R.id.parity_bits_1);
        Spinner stopBits1 = view.findViewById(R.id.stop_bits_1);
        receive1 = view.findViewById(R.id.receive1);
        command1 = view.findViewById(R.id.command_1);
        SwitchButton rs485Switch1 = view.findViewById(R.id.rs485_1_switch);
        rs485Switch1.setOnCheckedChangeListener(new SwitchButton.OnCheckedChangeListener() {
            @Override
            public void onCheckedChanged(SwitchButton view, boolean isChecked) {
                if (isChecked) {
//                    openSerialPort( initiateMode1.getSelectedItem().toString().trim(),Integer.parseInt((String) baudRate1.getSelectedItem()));
                    openSerialPort("/dev/ttyWCHUSB1",9600);
                    // 定时向板子发送指令
                    setTimer();
                }
                else close();
            }
        });

        SwitchButton rs485Switch2 = view.findViewById(R.id.rs485_2_switch);
        Spinner initiateMode2 = view.findViewById(R.id.initiate_mode_2);
        Spinner baudRate2 = view.findViewById(R.id.baud_rate_2);
        Spinner dataBits2 = view.findViewById(R.id.data_bits_2);
        Spinner parityBits2 = view.findViewById(R.id.parity_bits_2);
        Spinner stopBits2 = view.findViewById(R.id.stop_bits_2);

        EditText pollingCycle = view.findViewById(R.id.polling_cycle);
        EditText overtime = view.findViewById(R.id.overtime);
        EditText failTime = view.findViewById(R.id.fail_time);
        pollingCycle.setText("3000");
        overtime.setText("3000");
        failTime.setText("2000");*/
    }
    /**
     * 系统是否支持USB Host功能
     *
     * @return true:系统支持USB Host false:系统不支持USB Host
     */
    public boolean UsbFeatureSupported() {
        boolean bool = mContext.getPackageManager().hasSystemFeature(
                "android.hardware.usb.host");
        return bool;
    }
    RecyclerView deviceRecyclerVIew;
    DeviceAdapter deviceAdapter;
    //接收区
    TextView readBuffer;
    CustomTextView clearRead;
    SwitchCompat scRead;
    TextView readCount;
    void initUI(){
        deviceRecyclerVIew=mView.findViewById(R.id.rvDevice);
        /*readBuffer=mView.findViewById(R.id.tvReadData);
        clearRead=mView.findViewById(R.id.tvClearRead);
        scRead=mView.findViewById(R.id.scRead);
        readCount=mView.findViewById(R.id.tvReadCount);*/
        //初始化recyclerview
        deviceRecyclerVIew.setNestedScrollingEnabled(false);
        deviceAdapter =new DeviceAdapter(mActivity);

        deviceRecyclerVIew.setLayoutManager(new LinearLayoutManager(mContext,LinearLayoutManager.VERTICAL,false));
        View view = LayoutInflater.from(mContext).inflate(R.layout.empty_view, deviceRecyclerVIew, false);
        view.findViewById(R.id.empty_view).setOnClickListener(v -> enumDevice());
        deviceAdapter.setEmptyView(view);
        deviceRecyclerVIew.setAdapter(deviceAdapter);
        deviceAdapter.setActionListener(new DeviceAdapter.OnActionListener() {
            @Override
            public void onRemove(UsbDevice usbDevice) {
                removeReadDataDevice(usbDevice);
            }
        });

        readBuffer.setMovementMethod(ScrollingMovementMethod.getInstance());
        clearRead.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                clearReadData();
            }
        });
        //监测USB插拔状态
        monitorUSBState();
        //动态申请权限
        if(ContextCompat.checkSelfPermission(mContext, Manifest.permission.WRITE_EXTERNAL_STORAGE)!= PackageManager.PERMISSION_GRANTED){
            ActivityCompat.requestPermissions(mActivity,new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE},111);
        }
    }

    /**
     * 枚举当前所有符合要求的设备，显示设备列表
     */
    void enumDevice(){
        try {
            //枚举符合要求的设备
            ArrayList<UsbDevice> usbDeviceArrayList = CH934XManager.getInstance().enumDevice();
            if(usbDeviceArrayList.size()==0){
                showToast("no matched devices");
                return;
            }

            for (UsbDevice mUsbDevice : usbDeviceArrayList ){
                open(mUsbDevice);
            }
            //显示设备列表dialog
            /*DeviceListDialog deviceListDialog=DeviceListDialog.newInstance(usbDeviceArrayList);
            deviceListDialog.setCancelable(false);
            deviceListDialog.show(mActivity.getSupportFragmentManager(),DeviceListDialog.class.getName());
            deviceListDialog.setOnClickListener(new DeviceListDialog.OnClickListener() {
                @Override
                public void onClick(UsbDevice usbDevice) {
                    //选择了某一个设备打开
                    open(usbDevice);
                }
            });*/
        } catch (UartLibException e) {
            LogUtil.d(e.getMessage());
        }
    }

    /**
     * 从设备列表中打开某个设备
     *
     * @param usbDevice
     */
    void open(@NonNull UsbDevice usbDevice){
        if(CH934XManager.getInstance().isConnected(usbDevice)){
            showToast("当前设备已经打开");
            return;
        }
        try {
            boolean b = CH934XManager.getInstance().openDevice(usbDevice);
            if(b){
                //打开成功
                //更新显示的ui
                update(usbDevice);
                //初始化接收计数
                int serialCount = CH934XManager.getInstance().getSerialCount(usbDevice);
                for (int i = 0; i < serialCount; i++) {
                    readCountMap.put(FormatUtil.getSerialKey(usbDevice,i),0);
                }
                //将该设备添加至已打开设备列表,在读线程ReadThread中,将会读取该设备的每个串口数据
                addToReadDeviceSet(usbDevice);
                //用作文件对比测试,在打开每个设备时，对每个串口新建对应的保存数据的文件
               /* for (int i = 0; i < serialCount; i++) {
                    linkSerialToFile(usbDevice,i);
                }*/

            }else {
                showToast("打开失败");
            }
        } catch (ChipException e) {
            LogUtil.d(e.getMessage());
        } catch (NoPermissionException e) {
            //没有权限打开该设备
            //申请权限
            showToast("没有权限打开该设备");
            requestPermission(usbDevice);
        } catch (UartLibException e) {
            e.printStackTrace();
        }
    }

    /**
     * 申请读写权限
     * @param usbDevice
     */
    private void requestPermission(@NonNull UsbDevice usbDevice){
        try {
            CH934XManager.getInstance().requestPermission(mContext,usbDevice);
        } catch (UartLibException e) {
            LogUtil.d(e.getMessage());
        }
    }

    /**
     * 监测USB的状态
     */
    private void monitorUSBState(){
        CH934XManager.getInstance().setUsbStateListener(new IUsbStateChange() {
            @Override
            public void usbDeviceDetach(UsbDevice device) {
                //设备移除
                mActivity.runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        //从界面上移除
                        if(deviceAdapter!=null){
                            deviceAdapter.removeDevice(device);
                        }
                    }
                });

            }

            @Override
            public void usbDeviceAttach(UsbDevice device) {
                //设备插入
            }

            @Override
            public void usbDevicePermission(UsbDevice device, boolean result) {
                //请求打开设备权限结果
            }
        });
    }

    /**
     * //recyclerView更新UI
     * @param usbDevice
     */
    void update(UsbDevice usbDevice){
        //根据vid/pid获取芯片类型
        ChipType chipType = CH934XManager.getInstance().getChipType(usbDevice);
        //获取芯片串口数目,为负则代表出错
        int serialCount = CH934XManager.getInstance().getSerialCount(usbDevice);
        //构建recyclerView所绑定的数据,添加设备
        ArrayList<SerialEntity> serialEntities=new ArrayList<>();
        for (int i = 0; i < serialCount; i++) {
            SerialEntity serialEntity=new SerialEntity(usbDevice,i);
            serialEntities.add(serialEntity);
        }
        DeviceEntity deviceEntity=new DeviceEntity(usbDevice,chipType.getDescription(),serialEntities);
        if(deviceAdapter.hasExist(deviceEntity)){
            //已经显示
            showToast("该设备已经存在");
        }else {
            deviceAdapter.addDevice(deviceEntity);
        }
    }

    /**
     * 关闭所有设备
     */
    void closeAll(){
        ArrayList<UsbDevice> usbDeviceArrayList = null;
        try {
            usbDeviceArrayList = CH934XManager.getInstance().enumDevice();
            for (UsbDevice usbDevice : usbDeviceArrayList) {
                if(CH934XManager.getInstance().isConnected(usbDevice)){
                    CH934XManager.getInstance().disconnect(usbDevice);
                }
            }
        } catch (UartLibException e) {
            e.printStackTrace();
        }

    }

    private void addToReadDeviceSet(@NonNull UsbDevice usbDevice){
        synchronized (devices){
            devices.add(usbDevice);
        }

    }

    private void removeReadDataDevice(@NonNull UsbDevice usbDevice){
        synchronized (devices){
            devices.remove(usbDevice);
        }
    }
    byte[] allBytes = new byte[0];
    public class ReadThread extends Thread{

        public ReadThread() {
            flag=true;
            setPriority(Thread.MAX_PRIORITY);
        }

        @Override
        public void run() {
            LogUtil.d("---------------开始读取数据");
            while (flag){
                if(devices.isEmpty()){
                    continue;
                }
                //遍历已打开的设备列表中的设备
                synchronized (devices){
                    Iterator<UsbDevice> iterator = devices.iterator();
                    while (iterator.hasNext()){
                        UsbDevice device = iterator.next();
                        int serialCount = CH934XManager.getInstance().getSerialCount(device);
                        //读取该设备每个串口的数据

                        int num = 0;
                        for (int i = 0; i < serialCount; i++) {
                            try {
                                byte[] bytes = CH934XManager.getInstance().readData(device, i);
                                if(bytes!=null){
                                    num += i;
                                    allBytes = new byte[allBytes.length+bytes.length];
                                    System.arraycopy(bytes, 0, allBytes, 0, bytes.length);
                                    //界面显示数据

                                    //数据保存至文件
                                    //updateReadDataToFile(device,i,bytes,bytes.length);
                                }
                            } catch (ChipException e) {
                                //LogUtil.d(e.getMessage());
                                break;
                            }
                        }
                        if (allBytes.length > 8){
                            //updateReadData(device,num,allBytes,allBytes.length);
                            LogUtil.d("收到数据:---->allBytes.length" + allBytes.length + "   " + FormatUtil.bytesToHexString(allBytes));

                            allBytes = new byte[0];
                        }
                    }
                }
            }
            LogUtil.d("读取数据线程结束");
        }
    }

    public void stopReadThread(){
        if(readThread!=null && readThread.isAlive()){
            flag=false;
        }
    }

    private void updateReadData(@NonNull UsbDevice usbDevice,int serialNumber, byte[] buffer, int length){
        if(buffer==null){
            return;
        }
        mActivity.runOnUiThread(new Runnable() {
            @Override
            public void run() {
                Integer integer = readCountMap.get(FormatUtil.getSerialKey(usbDevice, serialNumber));
                if(integer==null){
                    //不包含此key
                    return;
                }
                //更新计数
                integer+=length;
                readCountMap.put(FormatUtil.getSerialKey(usbDevice, serialNumber),integer);
                //

                String result="";
                if (readBuffer.getText().toString().length() >= 1500) {
                    readBuffer.setText("");
                    readBuffer.scrollTo(0, 0);
                }

                if(scRead.isChecked()){
                    result= FormatUtil.bytesToHexString(buffer, length);

                }else {
                    result=new String(buffer,0,length);
                }
                String readBufferLogPrefix = FormatUtil.getReadBufferLogPrefix(usbDevice, serialNumber,integer);
                //LogUtil.d(readBufferLogPrefix);
                readBuffer.append(readBufferLogPrefix+result+"\n");

                int offset = (readBuffer.getLineCount() - 1) * readBuffer.getLineHeight();
                //int maxHeight = usbReadValue.getMaxHeight();
                int height = readBuffer.getHeight();
                //USBLog.d("offset: "+offset+"  maxHeight: "+maxHeight+" height: "+height);
                if (offset > height) {
                    //USBLog.d("scroll: "+(offset - usbReadValue.getHeight() + usbReadValue.getLineHeight()));
                    readBuffer.scrollTo(0, offset - readBuffer.getHeight() + readBuffer.getLineHeight());
                }
            }
        });
    }


    private void clearReadData(){
        readBuffer.scrollTo(0,0);
        readBuffer.setText("");
        for (String s : readCountMap.keySet()) {
            readCountMap.put(s,0);
        }
    }

    private void showToast(String message){
        mActivity.runOnUiThread(new Runnable() {
            @Override
            public void run() {
                ToastUtil.create(mContext,message).show();
            }
        });
    }
    ///////////////////////////////////////将数据保存至文件,与发送文件对比测试////////////////////////////////////////////////////

    //该Map的key是每个设备的串口，value是其对应的保存数据的文件的fileStream
    private HashMap<String, FileOutputStream> fileOutputStreamMap=new HashMap<>();

    //用作文件对比测试,在打开每个设备时，每个串口都新建对应的保存数据的文件，其映射关系保存到fileOutputStreamMap中
    private void linkSerialToFile(UsbDevice usbDevice,int serialNumber){
        LogUtil.d("linkSerialToFile:");
        File testFile = mActivity.getExternalFilesDir("TestFile");
        File file=new File(testFile,CH934XManager.getInstance().getChipType(usbDevice).toString()+"_"+serialNumber+".txt");
        if(file.exists()){
            file.delete();
        }
        try {
            boolean ret = file.createNewFile();
            LogUtil.d("新建文件:"+ret);
            FileOutputStream fileOutputStream = new FileOutputStream(file);
            if(!fileOutputStreamMap.containsKey(FormatUtil.getSerialKey(usbDevice,serialNumber))){
                fileOutputStreamMap.put(FormatUtil.getSerialKey(usbDevice,serialNumber),fileOutputStream);
            }
        } catch (IOException e) {
            LogUtil.d(e.getMessage());
        }

    }

    //010300000002C40B
    //将接收到的数据保存至文件，用作对比
    private void updateReadDataToFile(@NonNull UsbDevice usbDevice,int serialNumber, byte[] buffer, int length){
        updateToFile(usbDevice, serialNumber, buffer, length);
    }

    private void updateToFile(@NonNull UsbDevice usbDevice,int serialNumber, byte[] buffer, int length){
        if(fileOutputStreamMap.containsKey(FormatUtil.getSerialKey(usbDevice,serialNumber))){
            FileOutputStream fileOutputStream = fileOutputStreamMap.get(FormatUtil.getSerialKey(usbDevice, serialNumber));
            try {
                fileOutputStream.write(buffer,0,length);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
    /*private SerialPortFinder mSerialPortFinder;
    private Vector<String> vectorList;
    private Vector<String> getAllDevices(){

        if (mSerialPortFinder == null) mSerialPortFinder = new SerialPortFinder();
        // 得到所有设备文件地址的数组
        // 实际上该操作并不需要，这里只是示例打印出所有的设备信息
        Vector<String> allVectorList = mSerialPortFinder.getAllDevicesPath();
//        String[] allVectorList = new String[]{"/dev/ttyS0","/dev/ttyS1","/dev/ttyS3","/dev/ttyS4"};

        if (vectorList == null) vectorList = new Vector<>();
        vectorList.clear();
        for (String vector : allVectorList){
            if (vector.contains("WCH"))
            vectorList.add(vector.trim());
        }
        return vectorList;
    }


    private ScheduledExecutorService executorService;
    private void setTimer(){
        executorService = Executors.newSingleThreadScheduledExecutor();
        executorService.scheduleAtFixedRate(new Runnable() {
            @Override
            public void run() {
                mHandler.sendEmptyMessage(123);
            }
        }, 0, 3000, TimeUnit.MILLISECONDS);
    }

    @SuppressLint("HandlerLeak")
    private Handler mHandler = new Handler(){
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            if (msg.what == 123) {// 向板子写入指令
                writeHexToBoard(command1.getText().toString().trim());
            }
        }
    };

    private DataTurn mDataTurn;
    private InputStream mInputStream;
    private OutputStream mOutputStream;
    private SerialPort mSerialPort;
    private boolean first = true;

    private void openSerialPort(String pathName, int port) {
        try {
            mSerialPort = new SerialPort(new File(pathName), port, 0);
            // 获取输入输出流
            mInputStream = mSerialPort.getInputStream();
            mOutputStream = mSerialPort.getOutputStream();

            if (first){
                first = false;
                readReturnResult();
            }
            Log.d(TAG,"串口打开成功");
        } catch (IOException e) {
            Log.d(TAG,"找不到该设备文件");
        }
    }

    public void writeHexToBoard(String inHex) {
        if (inHex.isEmpty()) {
            Log.d(TAG,"内容为空，请检查");
            return;
        }
        if (mOutputStream == null){
            Log.d(TAG,"send:(" + inHex + ")  发送失败，未打开串口");
            return;
        }
        if (isSpecialChar(inHex)){
            Log.d(TAG,"send:(" + inHex + ")  发送失败，存在非十六进制字符");
            return;
        }
        byte[] bytes = mDataTurn.HexToByteArr(inHex);

        // 写入数据
        try {
            mOutputStream.write(bytes);
            mOutputStream.flush();
            Log.d(TAG,"send:(" + inHex + ")  发送成功");
        } catch (IOException e) {
            Log.d(TAG,"send:(" + inHex + ")  发送失败,流写入异常");
            e.printStackTrace();
        }
    }

    public boolean isSpecialChar(String str) {
        String regEx = "[ _`~!@#$%^&*()+=|{}':;',\\[\\].<>/?~！@#￥%……&*（）——+|{}【】‘；：”“’。，、？g-zG-Z]|\n|\r|\t";
        Pattern p = Pattern.compile(regEx);
        Matcher m = p.matcher(str);
        return m.find();
    }

    private ReadThread readThread;
    private void readReturnResult(){
        // 开启子线程，不断读取返回结果
        if (mDataTurn == null) mDataTurn = new DataTurn();
        if (readThread == null) readThread = new ReadThread();
        readThread.start();
    }
    boolean flag = true;
    private class ReadThread1 extends Thread {
        @Override
        public void run() {
            super.run();

            while (flag) {
                try {
                    if (mInputStream.available() <= 0) {
                        continue;
                    } else {
                        Thread.sleep(200);
                    }
                    byte[] buffer = new byte[128];
                    int size = mInputStream.read(buffer);
                    byte[] readBytes = new byte[size];
                    System.arraycopy(buffer, 0, readBytes, 0, size);
                    Log.d(TAG,"float data is--->:" + mDataTurn.ByteArrToFloat(readBytes));
                    receive1.setText("接收：" + mDataTurn.ByteArrToHex(readBytes));
                }catch (Exception e){
                    e.printStackTrace();
                    try { Thread.sleep(2000); } catch (InterruptedException ex) { }
                }
            }
        }
    }

    private void close(){
        flag = false;
        if (readThread != null){
            readThread.interrupt();
            readThread = null;
        }

        if (mInputStream != null) {
            try {
                mInputStream.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        if (mOutputStream != null){
            try {
                mOutputStream.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        if (mSerialPort != null)
            mSerialPort.close();

        if (mHandler != null){
            mHandler.removeCallbacksAndMessages(null);
        }
        if (executorService != null){
            executorService.shutdownNow();
            executorService = null;
        }
    }*/
}
